///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef _ResourceManager_H__
#define _ResourceManager_H__

#include "OgrePrerequisites.h"

#include "OgreResource.h"
#include "OgreResourceGroupManager.h"
#include "OgreIteratorWrappers.h"
#include "OgreCommon.h"
#include "OgreDataStream.h"
#include "OgreStringVector.h"
#include "OgreScriptLoader.h"

namespace Ogre {

	class _OgreExport ResourceManager : public ScriptLoader, public MemAlloc_Resource
    {
    public:
		OGRE_AUTO_MUTEX // public to allow external locking
        ResourceManager();
        virtual ~ResourceManager();

        
        virtual ResourcePtr create(const String& name, const String& group, 
            bool isManual = false, ManualResourceLoader* loader = 0, 
            const NameValuePairList* createParams = 0);

		typedef std::pair<ResourcePtr, bool> ResourceCreateOrRetrieveResult;
		
		virtual ResourceCreateOrRetrieveResult createOrRetrieve(const String& name, 
			const String& group, bool isManual = false, 
			ManualResourceLoader* loader = 0, 
			const NameValuePairList* createParams = 0);
		
        
        virtual void setMemoryBudget( size_t bytes);

        
        virtual size_t getMemoryBudget(void) const;

		
		virtual size_t getMemoryUsage(void) const { return mMemoryUsage.get(); }

		
		virtual void unload(const String& name);
		
		
		virtual void unload(ResourceHandle handle);

		
		virtual void unloadAll(bool reloadableOnly = true);

		
		virtual void reloadAll(bool reloadableOnly = true);

		
		virtual void unloadUnreferencedResources(bool reloadableOnly = true);

		
		virtual void reloadUnreferencedResources(bool reloadableOnly = true);

		
		virtual void remove(ResourcePtr& r);

        
		virtual void remove(const String& name);
		
		
		virtual void remove(ResourceHandle handle);
		
        virtual void removeAll(void);

		
		virtual void removeUnreferencedResources(bool reloadableOnly = true);

        
        virtual ResourcePtr getByName(const String& name, const String& groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
        
        virtual ResourcePtr getByHandle(ResourceHandle handle);
		
		/// Returns whether the named resource exists in this manager
		virtual bool resourceExists(const String& name)
		{
			return !getByName(name).isNull();
		}
		/// Returns whether a resource with the given handle exists in this manager
		virtual bool resourceExists(ResourceHandle handle)
		{
			return !getByHandle(handle).isNull();
		}

		
		virtual void _notifyResourceTouched(Resource* res);

		
		virtual void _notifyResourceLoaded(Resource* res);

		
		virtual void _notifyResourceUnloaded(Resource* res);

		
		virtual ResourcePtr prepare(const String& name, 
            const String& group, bool isManual = false, 
			ManualResourceLoader* loader = 0, const NameValuePairList* loadParams = 0,
			bool backgroundThread = false);

		
		virtual ResourcePtr load(const String& name, 
            const String& group, bool isManual = false, 
			ManualResourceLoader* loader = 0, const NameValuePairList* loadParams = 0,
			bool backgroundThread = false);

		
		virtual const StringVector& getScriptPatterns(void) const { return mScriptPatterns; }

		
		virtual void parseScript(DataStreamPtr& stream, const String& groupName)
                { (void)stream; (void)groupName; }

		
		virtual Real getLoadingOrder(void) const { return mLoadOrder; }

		
		const String& getResourceType(void) const { return mResourceType; }

        
        virtual void setVerbose(bool v) { mVerbose = v; }

        
        virtual bool getVerbose(void) { return mVerbose; }

		
		class _OgreExport ResourcePool : public Pool<ResourcePtr>, public MemAlloc_Resource
		{
		protected:
			String mName;
		public:
			ResourcePool(const String& name);
			~ResourcePool();
			/// Get the name of the pool
			const String& getName() const;
			void clear();
		};
		
		/// Create a resource pool, or reuse one that already exists
		ResourcePool* getResourcePool(const String& name);
		/// Destroy a resource pool
		void destroyResourcePool(ResourcePool* pool);
		/// Destroy a resource pool
		void destroyResourcePool(const String& name);
		/// destroy all pools
		void destroyAllResourcePools();




    protected:

        
        ResourceHandle getNextHandle(void);

		
		virtual Resource* createImpl(const String& name, ResourceHandle handle, 
			const String& group, bool isManual, ManualResourceLoader* loader, 
            const NameValuePairList* createParams) = 0;
		
		virtual void addImpl( ResourcePtr& res );
		
		virtual void removeImpl( ResourcePtr& res );
		
		virtual void checkUsage(void);


    public:
		typedef HashMap< String, ResourcePtr > ResourceMap;
		typedef HashMap< String, ResourceMap > ResourceWithGroupMap;
		typedef map<ResourceHandle, ResourcePtr>::type ResourceHandleMap;
    protected:
        ResourceHandleMap mResourcesByHandle;
        ResourceMap mResources;
		ResourceWithGroupMap mResourcesWithGroup;
        ResourceHandle mNextHandle;
        size_t mMemoryBudget; // In bytes
        AtomicScalar<size_t> mMemoryUsage; // In bytes

        bool mVerbose;

		// IMPORTANT - all subclasses must populate the fields below

		/// Patterns to use to look for scripts if supported (e.g. *.overlay)
		StringVector mScriptPatterns; 
		/// Loading order relative to other managers, higher is later
		Real mLoadOrder; 
		/// String identifying the resource type this manager handles
		String mResourceType; 

    public:
        typedef MapIterator<ResourceHandleMap> ResourceMapIterator;
        
        ResourceMapIterator getResourceIterator(void) 
        {
            return ResourceMapIterator(mResourcesByHandle.begin(), mResourcesByHandle.end());
        }

	protected:
		typedef map<String, ResourcePool*>::type ResourcePoolMap;
		ResourcePoolMap mResourcePoolMap;


    

    };
	
	

}

#endif
